package com.zql.sqlSession;


import com.zql.Configuration;
import com.zql.MappedStatement;

import java.lang.reflect.*;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

public class DefaultSqlSession implements SqlSession {
    private final Configuration configuration;

    public DefaultSqlSession(Configuration configuration) {
        this.configuration = configuration;
    }

    private final Executor simpleExcutor = new SimpleExecutor();

    public Connection getConnection() throws SQLException {
        //1.注册驱动，获取连接
        return configuration.getDataSource().getConnection();
    }

    public <E> List<E> selectList(MappedStatement mappedStatement, Object... param) throws Exception {
        List<E> query = simpleExcutor.query(this.getConnection(), mappedStatement, param);
        return query;
    }

    public <T> T selectOne(MappedStatement mappedStatement, Object... params) throws Exception {
        List<Object> objects = selectList(mappedStatement, params);
        if (objects.size() == 1) {
            return (T) objects.get(0);
        } else {
            throw new RuntimeException("返回结果过多");
        }
    }


    public int CUDUser(MappedStatement mappedStatement, Object... param) throws Exception {
        int record = simpleExcutor.CUD(this.getConnection(), mappedStatement, param);
        return record;
    }


    @Override
    public <T> T getMapper(Class<?> mapperClass) {
        //使用JDK动态代理来为Dao接口生成代理对象，并返回
        T o = (T) Proxy.newProxyInstance(mapperClass.getClassLoader(), new Class[]{mapperClass}, new InvocationHandler() {
            // proxy:当前代理对象的应用，method:当前被调用的方法,args:传递的参数
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //获取方法名
                String methodName = method.getName();
                //该方法的类的全限定名
                String className = method.getDeclaringClass().getName();
                //statementid,sql语句的唯一标识 = 接口全限定名.方法名
                String statementId = className + "." + methodName;

                MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
                if ("select".equals(mappedStatement.getSqlCommandType())) {
                    Type genericReturnType = method.getGenericReturnType(); //获取方法的返回值类型
                    //判断是否进行了泛型类型参数化，大白话就是说 判断当前这个返回值类型是否有泛型，如果有就认为返回值是集合类型，否则就是实体类型。
                    if (genericReturnType instanceof ParameterizedType) {
                        return selectList(mappedStatement, args);
                    }
                    return selectOne(mappedStatement, args);
                } else {
                    return CUDUser(mappedStatement, args);
                }

            }
        });
        return o;
    }
}
